﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Configuration;
using System.Collections.Specialized;
using System.Reflection;
using System.IO;
using System.Diagnostics;

namespace PickGold.Base
{
	public static class AssemblyConfig
	{
		/// <summary>
		/// 程序集配置信息
		/// </summary>
		private static Dictionary<Assembly, XmlDocument> _ConfigDictionary;

		/// <summary>
		/// Configuration
		/// </summary>
		private static Configuration _Configuration = null;
		private static Dictionary<string, NameValueCollection> _ConfigurationSectionDictionary;

		#region Config

		/// <summary>
		/// 配置信息
		/// </summary>
		public static XmlDocument Config
		{
			get
			{
				var xn = AssemblyConfig.GetConfigpDocument_lock(Assembly.GetCallingAssembly());
				if (xn.OwnerDocument == null)
					return xn as XmlDocument;

				return xn.OwnerDocument;
			}
		}

		/// <summary>
		/// 取配置信息
		/// </summary>
		/// <param name="target">程序集或类型或类实例，定义配置文件</param>
		/// <param name="path">路径</param>
		/// <returns>返回所选节点，如不存在则返回空值。</returns>
		public static XmlNode GetConfig(object target, string path)
		{
			if (target == null)
				target = Assembly.GetCallingAssembly();
			lock (typeof(AssemblyConfig).AssemblyQualifiedName + Environment.NewLine + MethodBase.GetCurrentMethod().Name)
				return AssemblyConfig.InnerGetConfig(target, path, 0, null);
		}

		/// <summary>
		/// 取配置信息
		/// </summary>
		/// <param name="target">程序集或类型或类实例，定义配置文件</param>
		/// <param name="path">路径</param>
		/// <param name="index">索引</param>
		/// <returns>返回所选节点，如不存在则返回空值。</returns>
		public static XmlNode GetConfig(object target, string path, int index)
		{
			if (target == null)
				target = Assembly.GetCallingAssembly();
			lock (typeof(AssemblyConfig).AssemblyQualifiedName + Environment.NewLine + MethodBase.GetCurrentMethod().Name)
				return AssemblyConfig.InnerGetConfig(target, path, index, null);
		}

		/// <summary>
		/// 取配置信息
		/// </summary>
		/// <param name="target">程序集或类型或类实例，定义配置文件</param>
		/// <param name="path">路径</param>
		/// <param name="attribute">属性名</param>
		/// <returns>返回所选节点，如不存在则返回空值。</returns>
		public static XmlNode GetConfig(object target, string path, string attribute)
		{
			if (target == null)
				target = Assembly.GetCallingAssembly();
			lock (typeof(AssemblyConfig).AssemblyQualifiedName + Environment.NewLine + MethodBase.GetCurrentMethod().Name)
				return AssemblyConfig.InnerGetConfig(target, path, 0, attribute);
		}

		/// <summary>
		/// 取配置信息
		/// </summary>
		/// <param name="target">程序集或类型或类实例，定义配置文件</param>
		/// <param name="path">路径</param>
		/// <param name="index">索引</param>
		/// <param name="attribute">属性名</param>
		/// <returns>返回所选节点，如不存在则返回空值。</returns>
		public static XmlNode GetConfig(object target, string path, int index, string attribute)
		{
			if (target == null)
				target = Assembly.GetCallingAssembly();
			lock (typeof(AssemblyConfig).AssemblyQualifiedName + Environment.NewLine + MethodBase.GetCurrentMethod().Name)
				return AssemblyConfig.InnerGetConfig(target, path, index, attribute);
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="target"></param>
		/// <param name="path"></param>
		/// <param name="index"></param>
		/// <param name="attribute"></param>
		/// <returns></returns>
		private static XmlNode InnerGetConfig(object target, string path, int index, string attribute)
		{
			if (target == null)
				target = Assembly.GetCallingAssembly();
			var xn = AssemblyConfig.GetConfigpDocument_lock(target);
			if (xn.OwnerDocument == null && xn is XmlDocument)
				xn = (xn as XmlDocument).DocumentElement;
			if (!string.IsNullOrEmpty(path) && path != "/" && index >= 0)
			{
				var ns = xn.SelectNodes(path);
				if (ns == null || index >= ns.Count)
					return null;

				xn = ns[index];
			}
			if (string.IsNullOrEmpty(attribute) || xn == null || xn.Attributes == null)
				return xn;

			return xn.Attributes[attribute];
		}

		/// <summary>
		/// 设置配置信息
		/// </summary>
		/// <param name="value">值</param>
		/// <param name="target">程序集或类型或类实例，定义配置文件</param>
		/// <param name="path">路径</param>
		/// <returns>是否成功，成功返回零，失败返回非零值，可根据返回值判断失败原因。</returns>
		public static int SetConfig(string value, object target, string path)
		{
			if (target == null)
				target = Assembly.GetCallingAssembly();
			return AssemblyConfig.SetConfig(value, target, path, 0, null);
		}

		/// <summary>
		/// 设置配置信息
		/// </summary>
		/// <param name="value">值</param>
		/// <param name="target">程序集或类型或类实例，定义配置文件</param>
		/// <param name="path">路径</param>
		/// <param name="index">索引</param>
		/// <returns>是否成功，成功返回零，失败返回非零值，可根据返回值判断失败原因。</returns>
		public static int SetConfig(string value, object target, string path, int index)
		{
			if (target == null)
				target = Assembly.GetCallingAssembly();
			return AssemblyConfig.SetConfig(value, target, path, index, null);
		}

		/// <summary>
		/// 设置配置信息
		/// </summary>
		/// <param name="value">值</param>
		/// <param name="target">程序集或类型或类实例，定义配置文件</param>
		/// <param name="path">路径</param>
		/// <param name="attribute">属性名</param>
		/// <returns>是否成功，成功返回零，失败返回非零值，可根据返回值判断失败原因。</returns>
		public static int SetConfig(string value, object target, string path, string attribute)
		{
			if (target == null)
				target = Assembly.GetCallingAssembly();
			return AssemblyConfig.SetConfig(value, target, path, 0, attribute);
		}

		/// <summary>
		/// 设置配置信息
		/// </summary>
		/// <param name="value">值</param>
		/// <param name="target">程序集或类型或类实例，定义配置文件</param>
		/// <param name="path">路径</param>
		/// <param name="index">索引</param>
		/// <param name="attribute">属性名</param>
		/// <returns>是否成功，成功返回零，失败返回非零值，可根据返回值判断失败原因。</returns>
		public static int SetConfig(string value, object target, string path, int index, string attribute)
		{
			if (target == null)
				target = Assembly.GetCallingAssembly();
			var xn = AssemblyConfig.GetConfigpDocument_lock(target);
			if (xn.OwnerDocument == null && xn is XmlDocument)
				xn = (xn as XmlDocument).DocumentElement;
			if (!string.IsNullOrEmpty(path) && path != "/" && index >= 0)
			{
				var ns = xn.SelectNodes(path);
				if (ns == null || index >= ns.Count)
					return 1;

				xn = ns[index];
			}
			if (string.IsNullOrEmpty(attribute))
				xn.Value = value;
			else if (xn.Attributes[attribute] == null)
				xn.Attributes.Append(xn.OwnerDocument.CreateAttribute(attribute)).Value = value;
			else
				xn.Attributes[attribute].Value = value;
			AssemblyConfig.SaveConfig(xn);
			return 0;
		}

		/// <summary>
		/// 创建配置节点
		/// </summary>
		/// <param name="parent">上级节点</param>
		/// <param name="name">名称</param>
		/// <param name="isAttribute">是否为属性</param>
		/// <returns>是否成功，成功返回零，失败返回非零值，可根据返回值判断失败原因。</returns>
		public static XmlNode CreateConfig(XmlNode parent, string name, bool isAttribute)
		{
			if (parent == null || parent.OwnerDocument == null)
				return null;

			if (isAttribute)
				parent = parent.Attributes.Append(parent.OwnerDocument.CreateAttribute(name));
			else
				parent = parent.AppendChild(parent.OwnerDocument.CreateElement(name));
			AssemblyConfig.SaveConfig(parent);
			return parent;
		}

		/// <summary>
		/// 保存配置
		/// </summary>
		/// <param name="node">配置节点</param>
		/// <returns>是否成功，零为成功，非零值则表示保存失败。</returns>
		public static int SaveConfig(XmlNode node)
		{
			var xml = node.OwnerDocument;
			if (xml == null)
				xml = node as XmlDocument;
			if (xml == null)
				return -1;

			foreach (var kvp in AssemblyConfig._ConfigDictionary)
			{
				if (kvp.Value == xml)
				{
					if (kvp.Value.DocumentElement.Attributes[kvp.Key.GetName().Name] == null ||
						string.IsNullOrEmpty(kvp.Value.DocumentElement.Attributes[kvp.Key.GetName().Name].Value))
						kvp.Value.Save(Path.ChangeExtension(kvp.Key.Location, "config"));
					else
						kvp.Value.Save(kvp.Value.DocumentElement.Attributes[kvp.Key.GetName().Name].Value);
					return 0;
				}
			}
			return -1;
		}

		/// <summary>
		/// 锁定
		/// </summary>
		/// <param name="target"></param>
		/// <param name="path"></param>
		/// <returns></returns>
		private static XmlNode GetConfigpDocument_lock(object target)
		{
			var sync_root = MethodBase.GetCurrentMethod() + string.Empty;
			lock (sync_root)
				return AssemblyConfig.GetConfigpDocument(target);
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="target"></param>
		/// <param name="path"></param>
		/// <returns></returns>
		private static XmlNode GetConfigpDocument(object target)
		{
			var xn = target as XmlNode;
			if (xn != null)
				return xn;

			var assembly = target as Assembly;
			if (assembly == null)
			{
				var type = target as Type;
				if (type == null)
				{
					if (target != null)
						type = target.GetType();
				}
				if (type != null)
					assembly = type.Assembly;
			}
			if (assembly == null)
			{
				var type = typeof(Common);
				var st = new StackTrace().GetFrames();
				foreach (var sf in st)
				{
					if (sf.GetMethod().DeclaringType != type)
					{
						type = sf.GetMethod().DeclaringType;
						break;
					}
				}
				assembly = type.Assembly;
			}

			if (AssemblyConfig._ConfigDictionary == null)
				AssemblyConfig._ConfigDictionary = new Dictionary<Assembly, XmlDocument>();
			if (AssemblyConfig._ConfigDictionary.ContainsKey(assembly))
				return AssemblyConfig._ConfigDictionary[assembly];

			AssemblyConfig._ConfigDictionary.Add(assembly, null);
			AssemblyConfig._ConfigDictionary[assembly] = new XmlDocument();
			var xml = AssemblyConfig._ConfigDictionary[assembly];
			var file = Common.GetFile(assembly);
			if (!string.IsNullOrEmpty(file) && File.Exists(file))
			{
				try
				{
					xml.Load(file);
					if (xml.DocumentElement.Attributes[assembly.GetName().Name] == null)
						xml.DocumentElement.Attributes.Append(xml.CreateAttribute(assembly.GetName().Name)).Value = file;
					else if (string.Compare(xml.DocumentElement.Attributes[assembly.GetName().Name].Value, file, true) != 0)
						xml.DocumentElement.Attributes[assembly.GetName().Name].Value = file;
					return xml;
				}
				catch { }

				AssemblyConfig._ConfigDictionary[assembly] = new XmlDocument();
				xml = AssemblyConfig._ConfigDictionary[assembly];
			}
			file = assembly.GetName().Name;
			xml.AppendChild(AssemblyConfig._ConfigDictionary[assembly].CreateElement(file));
			xml.DocumentElement.Attributes.Append(xml.CreateAttribute(file)).Value = string.Empty;
			return xml;
		}

		#endregion

		#region Configuration

		/// <summary>
		/// HongShijin.config
		/// </summary>
		public static Configuration Configuration
		{
			get
			{
				if (AssemblyConfig._Configuration != null)
					return AssemblyConfig._Configuration;

				var t = Common.GetFile(string.Empty);
				if (string.IsNullOrEmpty(t))
					t = Common.GetFile("App.config");
				if (string.IsNullOrEmpty(t))
					t = Common.GetFile("Web.config");
				if (string.IsNullOrEmpty(t))
					throw new ConfigurationErrorsException("配置文件不存在！");

				var cfm = new ExeConfigurationFileMap();
				cfm.ExeConfigFilename = t;
				AssemblyConfig._Configuration = ConfigurationManager.OpenMappedExeConfiguration(cfm, ConfigurationUserLevel.None);
				return AssemblyConfig._Configuration;
			}
		}

		public static NameValueCollection GetConfigurationSection(string name)
		{
			if (string.IsNullOrEmpty(name))
				return null;

			if (AssemblyConfig._ConfigurationSectionDictionary == null)
				AssemblyConfig._ConfigurationSectionDictionary = new Dictionary<string, NameValueCollection>();
			if (AssemblyConfig._ConfigurationSectionDictionary.ContainsKey(name))
				return AssemblyConfig._ConfigurationSectionDictionary[name];

			var section = AssemblyConfig.Configuration.GetSection(name);
			var xml = new XmlDocument();
			xml.LoadXml(section.SectionInformation.GetRawXml());
			var config = AssemblyConfig.CreateNameValueSection(section.SectionInformation.GetParentSection(), null, xml.DocumentElement);
			AssemblyConfig._ConfigurationSectionDictionary.Add(name, config);
			return config;
		}

		/// <summary>
		/// 创建配置节处理程序。
		/// </summary>
		/// <param name="parent">父对象。</param>
		/// <param name="configContext">配置上下文对象。</param>
		/// <param name="section">节 XML 节点。</param>
		/// <returns>创建的节处理程序对象。</returns>
		public static NameValueCollection CreateNameValueSection(object parent, object configContext, XmlNode section)//IConfigurationSectionHandler
		{
			return AssemblyConfig.CreateNameValueSection(parent, configContext, section, true);
		}

		/// <summary>
		/// 创建配置节处理程序。
		/// </summary>
		/// <param name="parent">父对象。</param>
		/// <param name="configContext">配置上下文对象。</param>
		/// <param name="section">节 XML 节点。</param>
		/// <param name="attributes">是否包含传入节的属性，默认包含。</param>
		/// <returns>创建的节处理程序对象。</returns>
		public static NameValueCollection CreateNameValueSection(object parent, object configContext, XmlNode section, bool attributes)//IConfigurationSectionHandler
		{
			int i, j;
			string t, key, value;
			XmlNode xn;
			var nvc = new NameValueCollection();
			if (attributes && section.Attributes != null && section.Attributes.Count > 0)
			{
				for (i = 0; i < section.Attributes.Count; i++)
					nvc.Add(section.Attributes[i].Name, section.Attributes[i].Value);
			}
			for (i = 0; i < section.ChildNodes.Count; i++)
			{
				key = null;
				value = null;
				xn = section.ChildNodes[i];
				if (xn.NodeType == XmlNodeType.Comment)
					continue;

				for (j = 0; xn.Attributes != null && j < xn.Attributes.Count; j++)
				{
					t = xn.Attributes[j].Name;
					if (string.Compare(t, "key", true) == 0)
						key = xn.Attributes[j].Value;
					else if (string.Compare(t, "name", true) == 0)
						key = xn.Attributes[j].Value;
					else if (string.Compare(t, "text", true) == 0)
						value = xn.Attributes[j].Value;
					else if (string.Compare(t, "value", true) == 0)
						value = xn.Attributes[j].Value;
					else if (string.Compare(t, "content", true) == 0)
						value = xn.Attributes[j].Value;
				}
				if (key == null)//string.IsNullOrEmpty
					key = xn.Name;
				if (string.IsNullOrEmpty(key))
					continue;

				if (value == null)//string.IsNullOrEmpty
				{
					if (xn != null)
						value = xn.InnerText;
					else
						value = string.Empty;
				}
				nvc.Add(key, value);
			}
			return nvc;
		}

		#endregion
	}

	/// <summary>
	/// Name Value Collection Config
	/// </summary>
	public class NameValueCollectionConfig : Dictionary<string, NameValueCollection>, IConfigurationSectionHandler
	{
		private static NameValueCollectionConfig _Value;

		/// <summary>
		/// 
		/// </summary>
		public static NameValueCollectionConfig Values
		{
			get
			{
				if (NameValueCollectionConfig._Value == null)
					NameValueCollectionConfig._Value = new NameValueCollectionConfig();
				return NameValueCollectionConfig._Value;
			}
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="key"></param>
		/// <returns></returns>
		public NameValueCollection this[string key]
		{
			get
			{
				if (this.ContainsKey(key))
					return base[key];

				NameValueCollection nvc = ConfigurationManager.GetSection(key) as NameValueCollection;
				if (nvc == null)
					nvc = new NameValueCollection();
				this.Add(key, nvc);
				return nvc;
			}
		}

		#region IConfigurationSectionHandler 成员

		object IConfigurationSectionHandler.Create(object parent, object configContext, XmlNode section)
		{
			return AssemblyConfig.CreateNameValueSection(parent, configContext, section);
		}

		#endregion
	}

	/// <summary>
	/// 创建 XML 配置节处理程序。
	/// </summary>
	public sealed class XmlSectionConfig : IConfigurationSectionHandler
	{
		private object _Parent;
		private object _ConfigContext;
		private XmlNode _Section;
		private XmlDocument _Xml;

		/// <summary>
		/// 父对象。
		/// </summary>
		private object Parent
		{
			get
			{
				return this._Parent;
			}
		}

		/// <summary>
		/// 配置上下文对象。
		/// </summary>
		private object ConfigContext
		{
			get
			{
				return this._ConfigContext;
			}
		}

		/// <summary>
		/// 节 XML 节点。
		/// </summary>
		private XmlNode Section
		{
			get
			{
				return this._Section;
			}
		}

		/// <summary>
		/// 包含配置节节点内容的XML文档
		/// </summary>
		private XmlDocument Xml
		{
			get
			{
				if (this._Section == null)
					return null;

				if (this._Xml != null)
					return this._Xml;

				this._Xml = new XmlDocument();

				//var ms = new MemoryStream();
				//var xtw = XmlTextWriter.Create(ms);
				//this._Section.WriteTo(xtw);
				//xtw.Flush();
				//xtw.Close();
				//ms.Position = 0;
				//var xtr = new XmlTextReader(ms);
				//this._Xml.Load(xtr);
				//xtr.Close();
				//ms.Close();
				//ms.Dispose();

				this._Xml.LoadXml(this._Section.OuterXml);

				return this._Xml;
			}
		}

		#region IConfigurationSectionHandler 成员

		/// <summary>
		/// 创建 XML 配置节处理程序。
		/// </summary>
		/// <param name="parent">父对象。</param>
		/// <param name="configContext">配置上下文对象。</param>
		/// <param name="section">节 XML 节点。</param>
		/// <returns>创建的节处理程序对象。</returns>
		object IConfigurationSectionHandler.Create(object parent, object configContext, XmlNode section)
		{
			this._Parent = parent;
			this._ConfigContext = configContext;
			this._Section = section;
			return section;
		}

		#endregion
	}
}
